/**
* \file ScannerFSM.h Defines the Final State Machine.
*/
#ifndef _FSM_INCLUDE_
#define _FSM_INCLUDE_

#include "ScanBuffer.h"
#include "TokenHierarchy.h"
#include "SymtableInterface.h"
#include "Lexem.h"
#include <iostream>
#include <cerrno>
#include "ScannerFSMExceptions.h"


/**
* ScannerFSM Interface.
*/
class ScannerFSMInterface {
public:
	ScannerFSMInterface() {}
	virtual ~ScannerFSMInterface(){}
	/**
	 * Start of ScannerFSM
	 * @return The next valid token read out from the inputfile
	 */
	virtual Token* getNextToken() = 0;
	
	/**
	 * Set the file wich should be used.
	 * 
	 * \param filename			Path to file.
	 * \param bufferBlockSize	Defines the size of the buffer.
	 */
	virtual void setFile(char* filename, unsigned int bufferBlockSize) = 0;
};

/**
* Der Automat besitzt für jeden Zustand eine Funktion. Innerhalb der Funktionen finden Fallunterscheidungen statt
* und abhängig von der aktuellen Eingabe für der nächste Zustand / die nächst Funktion ermittelt.
*/
class ScannerFSM : public ScannerFSMInterface
{
	/// Pointer of the buffer
	ScanBuffer* buffer;
	/// Pointer of the symtable
	SymtableInterface* symtable;
	/// Current lexem
	Lexem* lex;
	/// Flag, if end state is reached
	bool endState;
	/// Flag, if end of file is reached
	bool eof;

	int counter;

public:
	/**
	* Constructor
	* \param symtable Symbol Tabel for the Identifiere
	*/
	ScannerFSM(SymtableInterface* symtable);

	~ScannerFSM();

	/**
	* Set the file wich should be used.
	* 
	* \param filename			Path to file.
	* \param bufferBlockSize	Defines the size of the buffer.
	*/
	void setFile(char* filename, unsigned int bufferBlockSize);
	
	/**
	* Start of ScannerFSM
	*/
	Token* getNextToken();
	
private:

	/**
	* Return the next "char" from buffer
	* char append into the vector
	*/
	char nextChar();
	
	/**
	* Rewinds the buffer and the vector with 1
	*/
	void unGetChar();

	/**
	* The scanner logic
	*/
	Token* s_start();

	/**
	* Token identifier
	*/
	Token* s_identifier();
	
	/**
	* Token plus
	*/
	Token* s_plus();
	
	/**
	* Token minus
	*/
	Token* s_minus();
	
	/**
	* Token multi
	*/
	Token* s_multi();
	
	/**
	* Token div
	*/
	Token* s_div();
	
	/**
	* Token int
	*/
	Token* s_int();
	
	/**
	* Token real state 0
	*/
	Token* s_real_0();
	
	/**
	* Token real state 1
	*/
	Token* s_real_1();
	
	/**
	* Token real state 2
	*/
	Token* s_real_2();
	
	/**
	* Token real state 3
	*/
	Token* s_real_3();
	
	/**
	* Token real state 4
	*/
	Token* s_real_4();
	
	/**
	* Token braket close
	*/
	Token* s_braket_close();
	
	/**
	* Token braket open
	*/
	Token* s_braket_open();
	
	/**
	* Token comment state 0
	*/
	Token* s_comment_0();
	
	/**
	* Token comment state 1
	*/
	Token* s_comment_1();
	
	
	/**
	* Token alloc
	*/
	Token* s_alloc();
	/**
	* Token colon
	*/
	Token* s_colon();

	/**
	* Token semicolon
	*/
	Token* s_semicolon();
	
	/**
	* Token comma
	*/
	Token* s_comma();
	
	/**
	* Exception definition
	*/
	void throwSyntaxException();
	
	/**
	* Insert into Symtabel definition
	* \param type The number of enum (0 to 3)
	* symtabel->lookup !=  NULL ==> symtable->insert
	*/
	Element* insertIntoSymtable(int type);

	/**
	* Return false or true
	* true -> from "0..9"
	* false -> ! "0..9"
	*/
	bool isCharNumeric(char c);
	
	/**
	* Return false or true
	* true -> from "A..Z" or "a..z"
	* false -> ! "A..Z" or "a..z" 
	*/
	bool isCharText(char c);
	
	/**
	* Return false or true
	* true -> "+,-,*,/"
	* false -> ! "+,-,*,/"
	*/
	bool isCharOperation(char c);
	
	/**
	* Return false or true
	* true -> "(,),;, ,tab,\n"
	* false -> ! "(,),;, ,tab,\n,"
	*/
	bool isCharDevider(char c);	

};

#endif
